package com.jxtc.enterprise.common.handler;

import com.jxtc.enterprise.common.exception.*;
import com.jxtc.enterprise.common.utils.Result;
import com.jxtc.enterprise.common.utils.ResultCode;
import com.jxtc.enterprise.common.utils.ResultGenerator;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;

import java.util.stream.Collectors;

/**
 * 全局异常处理
 */
@Slf4j
// todo 等上线时再启用此切面，当前开发测试中，出现问题直接抛出异常，便于问题定位；开发调试期间使用此切面会导致很多异常日志不打印
@RestControllerAdvice
public class GlobalExceptionHandler {
    /**
     * 类型转换错误（url链接错误或数据类型转换出错）
     *
     * @return msg = "页面丢失"
     */
    @ExceptionHandler(MethodArgumentTypeMismatchException.class)
    public Result<String> errorPage(Exception e) {
        log.error("{}: {}", e.getClass(), e.getMessage());
        return ResultGenerator.genFailResult(ResultCode.NOT_FOUND, "页面丢失");
    }

    @ExceptionHandler(MethodArgumentNotValidException.class)
    public Result<String> paramValid(MethodArgumentNotValidException e) {
        return ResultGenerator.genFailResult(e.getAllErrors().stream()
                .map(DefaultMessageSourceResolvable::getDefaultMessage)
                .collect(Collectors.joining(",")));
    }

    /**
     * 更新失败时给出合理的提示信息
     *
     * @return msg = "xx 失败，请稍后重试"
     */
    @ExceptionHandler(ModifyFailureException.class)
    public Result<String> modifyFailed(Exception e) {
        log.error("{}: {}", e.getClass(), e.getMessage());
        return ResultGenerator.genFailResult(e.getMessage());
    }

    /**
     * 插入失败时给出合理的提示信息
     *
     * @return msg = "xx 失败，请稍后重试"
     */
    @ExceptionHandler(InsertFailureException.class)
    public Result<String> insertFailedHandler(Exception e) {
        log.error("{}: {}", e.getClass(), e.getMessage());
        return ResultGenerator.genFailResult(e.getMessage());
    }

    /**
     * 登录失败时给出合理的提示信息
     */
    @ExceptionHandler(LoginFailureException.class)
    public Result<Void> loginFailed(Exception e) {
        log.debug("{}: {}", e.getClass(), e.getMessage());
        return ResultGenerator.genFailResult(ResultCode.UNAUTHORIZED, e.getMessage());
    }

    /**
     * 传递的参数查询不到数据时返回该提示信息
     */
    @ExceptionHandler(IllegalArgumentException.class)
    public Result<Void> dataNotFound(Exception e) {
        log.error("{}: {}", e.getClass(), e.getMessage());
        return ResultGenerator.genFailResult(ResultCode.FAIL, e.getMessage());
    }

    /**
     * 用户已存在时返回该提示信息（TODO: 重构时可以考虑合并一些全局异常处理方法）
     */
    @ExceptionHandler(UserAlreadyExistException.class)
    public Result<Void> userAlreadyExists(Exception e) {
        log.error("{}: {}", e.getClass(), e.getMessage());
        return ResultGenerator.genFailResult(ResultCode.FAIL, e.getMessage());
    }

    /**
     * 前端未传递 token 时返回该提示信息，HTTP 状态码返回 401，错误信息返回异常信息
     */
    @ExceptionHandler(TokenMissingException.class)
    @ResponseStatus(HttpStatus.UNAUTHORIZED)
    public ResponseEntity<String> tokenMissingExceptionHandler(Exception e) {
        // log.error("{}: {}", e.getClass(), e.getMessage());
        return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(e.getMessage());
    }

    /**
     * 角色验证失败时返回该提示信息，HTTP 状态码返回 403，错误信息返回异常信息
     */
    @ExceptionHandler(RoleVerificationFailureException.class)
    @ResponseStatus(HttpStatus.FORBIDDEN)
    public ResponseEntity<String> roleVerificationFailure(Exception e) {
        // log.error("{}: {}", e.getClass(), e.getMessage());
        return ResponseEntity.status(HttpStatus.FORBIDDEN).body(e.getMessage());
    }
}
